/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openFuyao is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

// Package program 负责应用程序相关操作，目前只包含存在性检测
package program

import (
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"env-check/pkg/config"
	"env-check/pkg/logger"
)

// ApplicationChecker 程序检查器
type ApplicationChecker struct {
	config *config.AppConfig
	logger *logger.Logger
}

// NewProgramChecker 创建新的程序检查器
func NewProgramChecker(cfg *config.AppConfig, log *logger.Logger) *ApplicationChecker {
	return &ApplicationChecker{
		config: cfg,
		logger: log,
	}
}

// Execute 执行程序检查
func (p *ApplicationChecker) Execute() (*config.ProgramCheckResult, error) {
	p.logger.Info("program check start......")
	sysInfo := p.getSystemInfo()
	p.logger.Info(fmt.Sprintf("os： %s， arch： %s", sysInfo["os"], sysInfo["arch"]))
	p.logger.Info(fmt.Sprintf("program list to check: %v", p.config.ProgramList))

	result := &config.ProgramCheckResult{
		Timestamp: time.Now(),
		Programs:  make([]config.ProgramInfo, 0),
		Summary:   config.ProgramCheckSummary{},
	}

	// 检查所有程序
	for _, program := range p.config.ProgramList {
		programInfo := p.checkProgram(program)
		result.Programs = append(result.Programs, programInfo)
		p.updateProgramSummary(programInfo, result)
	}

	p.logger.Info("program check completed")
	return result, nil
}

// checkProgram 检查单个程序
func (p *ApplicationChecker) checkProgram(program string) config.ProgramInfo {
	p.logger.Info(fmt.Sprintf("check program: %s", program))

	info := config.ProgramInfo{
		Name: program,
	}

	// 查找程序路径
	path, err := exec.LookPath(program)
	if err != nil {
		info.Installed = false
		info.Error = fmt.Sprintf("not found: %v", err)
		p.logger.Info(fmt.Sprintf("not install: %s", program))
		return info
	}

	info.Installed = true
	info.Path = path

	// 尝试获取版本信息
	version, err := p.getProgramVersion(program)
	if err == nil {
		info.Version = version
		p.logger.Warning(fmt.Sprintf("%s installed - version: %s", program, version))
	} else {
		p.logger.Warning(fmt.Sprintf("%s installed - path: %s", program, path))
	}

	return info
}

// getProgramVersion 获取程序版本
func (p *ApplicationChecker) getProgramVersion(program string) (string, error) {
	var cmd = exec.Command(program, "--version")

	// 根据程序名称选择版本命令
	switch program {
	case "go":
		cmd = exec.Command("go", "version")
	case "java":
		cmd = exec.Command("java", "-version")
	case "kubectl":
		cmd = exec.Command("kubectl", "version", "--client")
	case "helm":
		cmd = exec.Command("helm", "version", "--short")
	default:
		// 默认尝试使用 --version 参数
		cmd = exec.Command(program, "--version")
	}

	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(string(output)), nil
}

// updateProgramSummary 更新程序检查汇总信息
func (p *ApplicationChecker) updateProgramSummary(programInfo config.ProgramInfo, result *config.ProgramCheckResult) {
	result.Summary.TotalChecked++

	if programInfo.Installed {
		result.Summary.TotalInstalled++
	} else {
		result.Summary.TotalMissing++
	}
}

// getSystemInfo 获取系统信息
func (p *ApplicationChecker) getSystemInfo() map[string]string {
	info := make(map[string]string)

	info["os"] = runtime.GOOS
	info["arch"] = runtime.GOARCH

	// 获取其他系统信息
	if hostname, err := os.Hostname(); err == nil {
		info["hostname"] = hostname
	}

	return info
}
